home *** CD-ROM | disk | FTP | other *** search
/ Programming Microsoft Visual Basic .NET / Programming Microsoft Visual Basic .NET (Microsoft Press)(X08-78517)(2002).bin / setup / vbnet / 13 threading / threadingdemo / module1.vb < prev    next >
Encoding:
Text File  |  2002-03-20  |  24.2 KB  |  737 lines

  1. Imports System.Threading
  2.  
  3. Module MainModule
  4.  
  5.     Sub Main()
  6.         ' Run one of the Textxxxx procedures below by uncommenting only one statement
  7.  
  8.         'TestThread()
  9.         'TestSuspendResume()
  10.         'TestJoin()
  11.         'TestInterrupt()
  12.         'TestThreadStatic()
  13.         'TestThreadLocalStorage()
  14.         'TestThreadData()
  15.         'TestEventNotifications()
  16.         'TestWrapperClass()
  17.         'TestSynchronizationProblem()
  18.         'TestSyncLock()
  19.         'TestSyncRoot()
  20.         'TestMonitorEnter()
  21.         'TestMonitorTryEnter()
  22.         'TestInterlocked()
  23.         'TestMutex()
  24.         'TestReaderWriterLock()
  25.         'TestAutoResetEvent()
  26.         'TestThreadPool()
  27.         'TestServerTimer()
  28.         'TestThreadingTimer()
  29.         'TestSynchronizationAttribute()
  30.  
  31.         ' You need these statements when running inside Visual Studio, so that
  32.         ' the Console window doesn't disappear
  33.         Console.WriteLine("")
  34.         Console.WriteLine(">>> Press Enter to terminate the program <<<")
  35.         Console.ReadLine()
  36.     End Sub
  37.  
  38.     ' this procedure tests basic thread capabilities
  39.  
  40.     Sub TestThread()
  41.         ' Create a new thread and define its starting point.
  42.         Dim t As New Thread(New ThreadStart(AddressOf DoTheTask))
  43.         ' Run the new thread.
  44.         t.Start()
  45.  
  46.         ' Print some messages to the Console window.
  47.         Dim i As Integer
  48.         For i = 1 To 10
  49.             Console.WriteLine("Msg #{0} from main thread (ID={1})", i, AppDomain.GetCurrentThreadId)
  50.             ' Wait for .2 seconds.
  51.             Thread.CurrentThread.Sleep(200)
  52.         Next
  53.     End Sub
  54.  
  55.     Sub DoTheTask()
  56.         Dim i As Integer
  57.         For i = 1 To 10
  58.             Console.WriteLine("Msg #{0} from secondary thread (ID={1})", i, AppDomain.GetCurrentThreadId)
  59.             ' wait for .2 seconds.
  60.             Thread.CurrentThread.Sleep(200)
  61.         Next
  62.     End Sub
  63.  
  64.     ' this procedure tests suspending and resuming threads
  65.  
  66.     Sub TestSuspendResume()
  67.         ' Define and start a new thread.
  68.         Dim t As New Thread(AddressOf DoTheTask)
  69.         t.Start()
  70.         Thread.Sleep(500)
  71.  
  72.         ' Suspend the thread.
  73.         Console.WriteLine("Suspending secondary thread.")
  74.         t.Suspend()
  75.         Thread.Sleep(500)
  76.  
  77.         ' Resume the thread.
  78.         Console.WriteLine("Resuming secondary thread.")
  79.         t.Resume()
  80.         Thread.Sleep(500)
  81.         ' ...
  82.         ' Abort the thread.
  83.         Console.WriteLine("Aborting secondary thread.")
  84.         t.Abort()
  85.     End Sub
  86.  
  87.     ' this procecure tests the Join method
  88.  
  89.     Sub TestJoin()
  90.         Dim t As New Thread(AddressOf DoTheTask)
  91.         t.Start()
  92.         Console.WriteLine("Waiting for the secondary thread to terminate")
  93.  
  94.         ' Wait for the other thread to die.
  95.         t.Join()
  96.         Console.WriteLine("Resuming the main thread")
  97.         Console.WriteLine("")
  98.  
  99.         t = New Thread(AddressOf DoTheTask)
  100.         t.Start()
  101.         Console.WriteLine("Starting another thread, again")
  102.  
  103.         ' Wait for the other thread to die, but print a message every second.
  104.         Do Until t.Join(1000)
  105.             Console.WriteLine("Waiting for the other thread to die...")
  106.         Loop
  107.         Console.WriteLine("Resuming the main thread")
  108.     End Sub
  109.  
  110.     ' this procedure tests the Interrupt method
  111.  
  112.     Sub TestInterrupt()
  113.         Dim t As New Thread(AddressOf DoTheTask2)
  114.         t.Start()
  115.         ' let it do some work, then interrupt it
  116.         Thread.Sleep(500)
  117.  
  118.         Console.WriteLine("Interrupting the secondary thread")
  119.         t.Interrupt()
  120.     End Sub
  121.  
  122.     ' a secondary thread that protects itself from the interrupt method
  123.  
  124.     Sub DoTheTask2()
  125.         Dim interrupted As Boolean
  126.  
  127.         ' emclose the entire working code in a Try block
  128.         Try
  129.             Dim i As Integer
  130.             For i = 1 To 10
  131.                 Console.WriteLine("Msg #" & i.ToString & " from secondary thread")
  132.                 ' wait for .2 seconds.
  133.                 Thread.CurrentThread.Sleep(200)
  134.             Next
  135.             ' We get here if the timeout elapsed and no exception is thrown.
  136.             ' (Not really necessary, because the variable is already False.)
  137.             interrupted = False
  138.         Catch ex As Exception
  139.             interrupted = True
  140.         Finally
  141.             ' print a suitable message
  142.             If interrupted Then
  143.                 Console.WriteLine("The thread was interrupted")
  144.             Else
  145.                 Console.WriteLine("The thread terminated normally.")
  146.             End If
  147.         End Try
  148.     End Sub
  149.  
  150.     ' this procedure tests the ThreadStatic attribute
  151.  
  152.     Sub TestThreadStatic()
  153.         Dim threads(10) As Thread
  154.         Dim i As Integer
  155.  
  156.         For i = 1 To 10
  157.             ' Create a new thread
  158.             threads(i) = New Thread(AddressOf DoTheTask3)
  159.             ' set its Name property
  160.             threads(i).Name = "thread #" & i.ToString
  161.             ' run it
  162.             threads(i).Start()
  163.         Next
  164.  
  165.         ' wait until all threads end
  166.         For i = 1 To 10
  167.             threads(i).Join()
  168.         Next
  169.     End Sub
  170.  
  171.     ' a variable that isn't shared among thread
  172.     <ThreadStatic()> Dim m_ThreadId As String
  173.  
  174.     Sub DoTheTask3()
  175.         ' Initialize the m_ThreadId variable with thread name
  176.         m_ThreadId = Thread.CurrentThread.Name
  177.  
  178.         ' signal that the thread has started
  179.         Console.WriteLine(Thread.CurrentThread.Name & " has started")
  180.         ' just wait for a while
  181.         Thread.CurrentThread.Sleep(2000)
  182.  
  183.         ' check that the m_ThreadID property hasn't been changed by other threads
  184.         If m_ThreadId = Thread.CurrentThread.Name Then
  185.             Console.WriteLine("m_ThreadID hasn't changed for " & Thread.CurrentThread.Name)
  186.         Else
  187.             Console.WriteLine("m_ThreadID *has* changed for " & Thread.CurrentThread.Name)
  188.         End If
  189.     End Sub
  190.  
  191.     ' this procedure tests Thread Local Storage
  192.  
  193.     Sub TestThreadLocalStorage()
  194.         ' Allocate a new unnamed TLS slot.
  195.         Dim slot As LocalDataStoreSlot = Thread.AllocateDataSlot()
  196.  
  197.         ' The AllocateNamedDataSlot method fails if the slot exists already.
  198.         Dim namedSlot As LocalDataStoreSlot = Thread.AllocateNamedDataSlot("id")
  199.  
  200.         ' The GetNamedDataSlot method returns a reference to an existing named slot
  201.         ' or creates a new slot if necessary.
  202.         Dim namedSlot2 As LocalDataStoreSlot = Thread.GetNamedDataSlot("id")
  203.  
  204.         ' Store a value in the slot created previously.
  205.         Thread.SetData(slot, 123)
  206.         ' ...
  207.         ' Read the value back.
  208.         Console.Write(Thread.GetData(slot))     ' => 123
  209.  
  210.         ' Destroys the slot named ID from all the threads in the current application.
  211.         Thread.FreeNamedDataSlot("id")
  212.     End Sub
  213.  
  214.     ' this procedure tests sharing data with a thread with DataClass
  215.  
  216.     Sub TestThreadData()
  217.         Dim i As Integer
  218.         Dim dc(9) As ThreadData
  219.         Dim t As Thread
  220.         Dim allDone As Boolean
  221.  
  222.         ' Create multiple threads.
  223.         For i = 0 To 9
  224.             ' Create a new data object and initialize its property
  225.             dc(i) = New ThreadData()
  226.             dc(i).Id = i + 1
  227.             dc(i).Msg = "A message"
  228.             ' Create a new thread and define its starting point.
  229.             t = New Thread(AddressOf dc(i).DoTheTask)
  230.             t.Start()
  231.         Next
  232.  
  233.         ' Poll until all threads have completed. 
  234.         ' (Just an example that retrieves values from threads.)
  235.         Do Until allDone
  236.             Console.WriteLine("Waiting...")
  237.             Thread.CurrentThread.Sleep(200)
  238.             ' Check that all threads have set Done=True.
  239.             allDone = True
  240.             For i = 0 To 9
  241.                 allDone = allDone And dc(i).Done
  242.             Next
  243.         Loop
  244.     End Sub
  245.  
  246.     ' this procedure tests using events for thread notifications
  247.  
  248.     ' NOTE: if you make this variable ThreadStatic, the program won't work any longer
  249.     ' because each thread will decrement a different copy of the variable.
  250.     '<ThreadStatic()> _
  251.     Dim runningThreads As Integer
  252.  
  253.     Sub TestEventNotifications()
  254.         Dim i As Integer
  255.         Dim dc(4) As ThreadData2
  256.         Dim t As Thread
  257.  
  258.         Thread.CurrentThread.Name = "Main thread"
  259.  
  260.         ' Create multiple threads.
  261.         For i = 0 To 4
  262.             ' Create a new data object and initialize its property
  263.             dc(i) = New ThreadData2()
  264.             dc(i).Id = i + 1
  265.             dc(i).Msg = "A message"
  266.             ' have this object's events point to the local event procedure
  267.             AddHandler dc(i).TaskCompleted, AddressOf TaskCompleted
  268.             ' Create a new thread and define its starting point.
  269.             t = New Thread(AddressOf dc(i).DoTheTask)
  270.             t.Name = "Thread #" & dc(i).Id.ToString
  271.             t.Start()
  272.             ' increment number of running threds
  273.             runningThreads += 1
  274.         Next
  275.  
  276.         ' Poll until all threads have completed. 
  277.         ' (Just an example that retrieves values from threads.)
  278.         Do Until runningThreads = 0
  279.             Console.WriteLine("Waiting...")
  280.             Thread.CurrentThread.Sleep(200)
  281.         Loop
  282.     End Sub
  283.  
  284.     ' an event procedure that runs when another thread terminates
  285.  
  286.     Sub TaskCompleted(ByVal Sender As Object, ByVal endTime As Date)
  287.         ' get the ID of the thread that terminated
  288.         Dim id As Integer = CType(Sender, ThreadData2).Id
  289.         ' display a message 
  290.         '        Console.WriteLine("Thread {0} terminated at {1}.", id, endTime)
  291.         Console.WriteLine("Thread {0} terminated (Running on {1})", id, Thread.CurrentThread.Name)
  292.         ' decrement counter of running threads.
  293.         runningThreads -= 1
  294.     End Sub
  295.  
  296.     ' this procedure tests the ThreadWrapperBase class
  297.  
  298.     Sub TestWrapperClass()
  299.         Dim i As Integer
  300.         Dim mytasks(10) As MyTask
  301.  
  302.         For i = 1 To 10
  303.             ' Initialize thread data, then start the thread.
  304.             mytasks(i) = New MyTask(i, "Message from thread")
  305.             mytasks(i).Thread.Name = "Thread #" & CStr(i)
  306.             mytasks(i).Start()
  307.         Next
  308.  
  309.         ' Wait until all tasks have completed.
  310.         For i = 1 To 10
  311.             Do Until mytasks(i).Done
  312.                 Console.WriteLine("Waiting...  (Main thread)")
  313.                 Thread.Sleep(200)
  314.             Loop
  315.         Next
  316.     End Sub
  317.  
  318.     ' this procedure shows problems caused by lack of synchronization
  319.  
  320.     Sub TestSynchronizationProblem()
  321.         ' Create five auxiliary threads.
  322.         Dim i As Integer
  323.         For i = 1 To 5
  324.             Dim t As New Thread(AddressOf DoTheTask4)
  325.             ' Assign a name to this thread, so that we can track its output.
  326.             t.Name = "Thread #" & i.ToString
  327.             t.Start()
  328.         Next
  329.     End Sub
  330.  
  331.     Sub DoTheTask4()
  332.         ' Print a lot of information to the console window.
  333.         Dim i As Integer
  334.         For i = 1 To 100
  335.             ' Split the output line in pieces.
  336.             Console.Write("Message ")
  337.             Console.Write("from ")
  338.             Console.WriteLine(Thread.CurrentThread.Name)
  339.             'Thread.Sleep(20)
  340.         Next
  341.     End Sub
  342.  
  343.     ' this procedure shows the solution based on SyncLock
  344.  
  345.     Sub TestSyncLock()
  346.         ' Create five auxiliary threads.
  347.         Dim i As Integer
  348.         For i = 1 To 5
  349.             Dim t As New Thread(AddressOf DoTheTask5)
  350.             ' Assign a name to this thread, so that we can track its output.
  351.             t.Name = "Thread #" & i.ToString
  352.             t.Start()
  353.         Next
  354.     End Sub
  355.  
  356.     ' The lock object (any non-Nothing value will do).
  357.     Dim consoleLock As String = "lock me"
  358.  
  359.     Sub DoTheTask5()
  360.         ' Print a lot of information to the console window.
  361.         Dim i As Integer
  362.         For i = 1 To 100
  363.             SyncLock consoleLock
  364.                 ' Split the output line in pieces.
  365.                 Console.Write("Message ")
  366.                 Console.Write("from ")
  367.                 Console.WriteLine(Thread.CurrentThread.Name)
  368.             End SyncLock
  369.         Next
  370.     End Sub
  371.  
  372.     ' this procedure tests the SyncRoot property
  373.  
  374.     Dim dblArr() As Double = {1.24, 456.9, 1.11, 99.34, 543.56}
  375.  
  376.     Sub TestSyncRoot()
  377.         Dim t As New Thread(AddressOf DoTheTask6)
  378.         t.Start()
  379.         t.Join()
  380.     End Sub
  381.  
  382.     Sub DoTheTask6()
  383.         Dim sum As Double
  384.         SyncLock dblArr.SyncRoot
  385.             ' Inside this block access to the ArrayList is thread-safe.
  386.             Dim d As Double
  387.             For Each d In dblArr
  388.                 sum += d
  389.             Next
  390.             Console.WriteLine("sum is {0}", sum)     ' => sum is 1102.15
  391.         End SyncLock
  392.     End Sub
  393.  
  394.     ' this procedure tests the Monitor.Enter / Exit methods
  395.  
  396.     Sub TestMonitorEnter()
  397.         ' Create five auxiliary threads.
  398.         Dim threads(5) As Thread
  399.  
  400.         Dim i As Integer
  401.         For i = 1 To 5
  402.             threads(i) = New Thread(AddressOf DoTheTask7)
  403.             ' Assign a name to this thread, so that we can track its output.
  404.             threads(i).Name = "Thread #" & i.ToString
  405.             threads(i).Start()
  406.         Next
  407.  
  408.         ' wait until all threads terminate
  409.         For i = 1 To UBound(threads)
  410.             threads(i).Join()
  411.         Next
  412.     End Sub
  413.  
  414.     Sub DoTheTask7()
  415.         ' Print a lot of information to the console window.
  416.         Dim i As Integer
  417.         For i = 1 To 100
  418.             Monitor.Enter(consoleLock)
  419.             ' Split the output line in pieces.
  420.             Console.Write("Message ")
  421.             Console.Write("from ")
  422.             Console.WriteLine(Thread.CurrentThread.Name)
  423.             Monitor.Exit(consoleLock)
  424.         Next
  425.     End Sub
  426.  
  427.     ' this procedure tests the Monitor.Enter / Exit methods
  428.  
  429.     Sub TestMonitorTryEnter()
  430.         ' Create five auxiliary threads.
  431.         Dim threads(5) As Thread
  432.  
  433.         Dim i As Integer
  434.         For i = 1 To 5
  435.             threads(i) = New Thread(AddressOf DoTheTask8)
  436.             ' Assign a name to this thread, so that we can track its output.
  437.             threads(i).Name = "Thread #" & i.ToString
  438.             threads(i).Start()
  439.         Next
  440.  
  441.         ' wait until all threads terminate
  442.         For i = 1 To UBound(threads)
  443.             threads(i).Join()
  444.         Next
  445.     End Sub
  446.  
  447.     Sub DoTheTask8()
  448.         ' Print a lot of information to the console window.
  449.         Dim i As Integer
  450.         For i = 1 To 100
  451.             Do Until Monitor.TryEnter(consoleLock, 10)
  452.                 Console.WriteLine("{0} failed to acquire the lock", Thread.CurrentThread.Name)
  453.             Loop
  454.  
  455.             ' Split the output line in pieces.
  456.             Console.Write("Message ")
  457.             Console.Write("from ")
  458.             Console.WriteLine(Thread.CurrentThread.Name)
  459.             ' Release the lock.
  460.             Monitor.Exit(consoleLock)
  461.         Next
  462.     End Sub
  463.  
  464.     ' this procedure tests the Interlocked class
  465.  
  466.     Sub TestInterlocked()
  467.         ' Create ten auxiliary threads.
  468.         Dim threads(10) As Thread
  469.  
  470.         Dim i As Integer
  471.         For i = 1 To 10
  472.             threads(i) = New Thread(AddressOf DoTheTask9)
  473.             ' Assign a name to this thread, so that we can track its output.
  474.             threads(i).Name = "Thread #" & i.ToString
  475.             threads(i).Start()
  476.         Next
  477.  
  478.         ' wait until all threads terminate
  479.         For i = 1 To UBound(threads)
  480.             threads(i).Join()
  481.         Next
  482.     End Sub
  483.  
  484.     ' Increment and Decrement methods work with 32-bit integers.
  485.     Dim lockCounter As Integer
  486.  
  487.     Sub DoTheTask9()
  488.         ' Print a lot of information to the console window.
  489.         Dim i As Integer
  490.  
  491.         ' Note that not all threads will print all the 100 messages
  492.  
  493.         For i = 1 To 100
  494.             ' Increment the lock counter and return the new value.
  495.             ' (Up to 4 threads are allowed to run in the critical section.)
  496.             If Interlocked.Increment(lockCounter) <= 4 Then
  497.                 ' display number of threads in the critical section
  498.                 Console.WriteLine("Message from {0}  ({1} threads running in critical section)", Thread.CurrentThread.Name, lockCounter)
  499.                 Thread.Sleep(10)
  500.             End If
  501.             ' Allow other threads to enter the critical section.
  502.             Interlocked.Decrement(lockCounter)
  503.         Next
  504.     End Sub
  505.  
  506.     ' this procedure tests the Mutex object
  507.  
  508.     ' three mutex objects, representing three available resources
  509.     Dim mutexes() As Mutex = {New Mutex(), New Mutex(), New Mutex()}
  510.  
  511.     Sub TestMutex()
  512.         ' Create ten auxiliary threads.
  513.         Dim threads(10) As Thread
  514.  
  515.         Dim i As Integer
  516.         For i = 1 To 10
  517.             threads(i) = New Thread(AddressOf DoTheTask10)
  518.             ' Assign a name to this thread, so that we can track its output.
  519.             threads(i).Name = "Thread #" & i.ToString
  520.             threads(i).Start()
  521.         Next
  522.  
  523.         ' wait until all threads terminate
  524.         For i = 1 To UBound(threads)
  525.             threads(i).Join()
  526.         Next
  527.     End Sub
  528.  
  529.     Sub DoTheTask10()
  530.         ' Print a lot of information to the console window.
  531.         Dim i As Integer
  532.         For i = 1 To 100
  533.             Dim mutexNdx As Integer = Mutex.WaitAny(mutexes)
  534.             ' use only the resource representing the mutexNdx.
  535.             Console.WriteLine("{0} is using Mutex #{1}", Thread.CurrentThread.Name, mutexNdx)
  536.             mutexes(mutexNdx).ReleaseMutex()
  537.         Next
  538.     End Sub
  539.  
  540.     ' This procedure tests the ReaderWriterLock class
  541.  
  542.     Dim rwl As New ReaderWriterLock()
  543.     Dim rnd As New Random()
  544.  
  545.     Sub TestReaderWriterLock()
  546.         Dim i As Integer
  547.         For i = 1 To 10
  548.             Dim t As New Thread(AddressOf DoTheTask12)
  549.             t.Name = i.ToString
  550.             t.Start()
  551.         Next
  552.         Thread.Sleep(20000)
  553.     End Sub
  554.  
  555.     Sub DoTheTask12()
  556.         Dim i As Integer
  557.         Dim tname As String = Thread.CurrentThread.Name()
  558.         ' Perform 10 read or write operations. (Reads are more frequent.)
  559.         For i = 1 To 10
  560.             If rnd.NextDouble < 0.8 Then
  561.                 ' Attempt a read operation.
  562.                 rwl.AcquireReaderLock(Timeout.Infinite)
  563.                 Console.WriteLine("Thread {0} is reading", tname)
  564.                 Thread.Sleep(300)
  565.                 Console.WriteLine("Thread {0} completed the read operation", _
  566.                     tname)
  567.                 rwl.ReleaseReaderLock()
  568.             Else
  569.                 ' Attempt a write operation.
  570.                 rwl.AcquireWriterLock(Timeout.Infinite)
  571.                 Console.WriteLine("Thread {0} is writing", tname)
  572.                 Thread.Sleep(300)
  573.                 Console.WriteLine("Thread {0} completed the write operation", _
  574.                     tname)
  575.                 rwl.ReleaseWriterLock()
  576.             End If
  577.         Next
  578.     End Sub
  579.  
  580.     ' This procedure tests the AutoResetEvent class
  581.  
  582.     ' The shared AutoResetEvent object
  583.     Public are As New AutoResetEvent(False)
  584.     ' The ArrayList where matching filenames should be added
  585.     Public filesAl As New ArrayList()
  586.     ' The number of running threads
  587.     Public searchingThreads As Integer
  588.  
  589.     Sub TestAutoResetEvent()
  590.         ' Search the file in all the subdirectories of C:
  591.         Dim dirname As String
  592.         For Each dirname In System.IO.Directory.GetDirectories("C:\")
  593.             Interlocked.Increment(searchingThreads)
  594.             ' Create a new wrapper class, pointing to a subdirectory.
  595.             Dim sf As New FileFinder(dirname, "*.zip")
  596.             ' Create a new thread for that subdirectory only, and run it.
  597.             Dim t As New Thread(AddressOf sf.StartSearch)
  598.             t.Start()
  599.         Next
  600.  
  601.         ' Remember how many results we have so far.
  602.         Dim resCount As Integer = 0
  603.         Do While searchingThreads > 0
  604.             ' Wait until there are new results.
  605.             are.WaitOne()
  606.  
  607.             ' Note that you should always use the SyncRoot property when using
  608.             ' an ArrayList and other collectionlike objects as lock objects.
  609.             SyncLock filesAl.SyncRoot
  610.                 ' Display names of all new results.
  611.                 Dim i As Integer
  612.                 For i = resCount To filesAl.Count - 1
  613.                     Console.WriteLine(filesAl(i))
  614.                 Next
  615.                 ' Remember that you've displayed these filenames.
  616.                 resCount = filesAl.Count
  617.             End SyncLock
  618.         Loop
  619.         Console.WriteLine("")
  620.         Console.WriteLine("Found {0} files", resCount)
  621.     End Sub
  622.  
  623.     ' this procedure tests the ThreadPool class
  624.  
  625.     Sub TestThreadPool()
  626.         Dim i As Integer
  627.         For i = 1 To 20
  628.             Try
  629.                 ' Create a new object for the next lightweight task.
  630.                 Dim task As New LightweightTask()
  631.                 ' Pass additional information to that object 
  632.                 ' (Not used in this demo).
  633.                 task.SomeData = "other data"
  634.                 ' Run the task with a thread from the pool
  635.                 ' (Pass the counter as an argument).
  636.                 ThreadPool.QueueUserWorkItem( _
  637.                    New WaitCallback(AddressOf task.DoTheTask), i)
  638.             Catch e As NotSupportedException
  639.                 Console.WriteLine("Failed (maybe a non-Windows 2000 system)")
  640.                 Exit Sub
  641.             End Try
  642.         Next
  643.  
  644.         ' Give all lightweight threads a chance to complete.
  645.         Thread.Sleep(4000)
  646.     End Sub
  647.  
  648.     ' this procedure tests the System.Timers.Timer class
  649.  
  650.     Dim WithEvents Timer As System.Timers.Timer
  651.     Dim eventCount As Integer
  652.  
  653.     Sub TestServerTimer()
  654.         ' Initialize the time to fire every  second.
  655.         ' (You can change it later through the Interval property.)
  656.         Timer = New System.Timers.Timer(1000)
  657.         ' True means it fires repeatedly, False means it fires only once.
  658.         Timer.AutoReset = True
  659.         ' Ensure the timer is enabled. (Same as Start method.)
  660.         Timer.Enabled = True
  661.  
  662.         ' Pause here until 5 events fire.
  663.         Do
  664.             Console.WriteLine("Message from main thread")
  665.             Thread.Sleep(100)
  666.         Loop Until eventCount = 5
  667.  
  668.         ' Stop the timer (not really necessary in this example).
  669.         Timer.Stop()        ' Same as Timer.Enabled = False.
  670.         ' Release all resources.
  671.         Timer.Close()
  672.     End Sub
  673.  
  674.     ' The Elapsed event    
  675.     Public Sub Timer_Elapsed(ByVal sender As Object, ByVal e As System.Timers.ElapsedEventArgs) Handles Timer.Elapsed
  676.         ' Display current system time in Output window.
  677.         Console.WriteLine("Event raised at {0}", e.SignalTime)
  678.         ' Remember how many events fired so far.
  679.         eventCount += 1
  680.     End Sub
  681.  
  682.     ' this procedure tests the System.Threading.Timer
  683.  
  684.     Sub TestThreadingTimer()
  685.         ' Get the first callback after 1 second
  686.         Dim dueTime As New TimeSpan(0, 0, 1)
  687.         ' get additional callbacks every half a second
  688.         Dim period As New TimeSpan(0, 0, 0, 0, 500)
  689.         ' create the timer 
  690.         Dim t As New System.Threading.Timer(New TimerCallback(AddressOf TimerProc), Nothing, dueTime, period)
  691.  
  692.         ' wait for 5 seconds in this demo.
  693.         Thread.Sleep(5000)
  694.  
  695.         ' destroy the timer 
  696.         t.Dispose()
  697.     End Sub
  698.  
  699.     ' the callback procedure
  700.  
  701.     Sub TimerProc(ByVal state As Object)
  702.         ' Display current system time in Output window.
  703.         Console.WriteLine("Callback proc called at {0}", Date.Now)
  704.     End Sub
  705.  
  706.     ' this procedure tests the Synchronization attribute
  707.  
  708.     Dim disp As New Display()
  709.  
  710.     Sub TestSynchronizationAttribute()
  711.         Dim i As Integer
  712.         Dim threads(10) As Thread
  713.         Dim o As New Object()
  714.  
  715.         For i = 1 To 10
  716.             threads(i) = New Thread(AddressOf DoTheTask11)
  717.             threads(i).Name = "Thread #" & i.ToString
  718.             threads(i).Start()
  719.         Next
  720.  
  721.         ' wait for all threads to terminate.
  722.         For i = 1 To UBound(threads)
  723.             threads(i).Join()
  724.         Next
  725.     End Sub
  726.  
  727.     Sub DoTheTask11()
  728.         ' Print a lot of information to the Output window.
  729.         Dim i As Integer
  730.         For i = 1 To 20
  731.             disp.DisplayData()
  732.         Next
  733.     End Sub
  734.  
  735. End Module
  736.  
  737.